/*
===========================================================================
Copyright (C) 2013-2014 Avotu Briezhaudzetava

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.

===========================================================================
*/

//
// includes
//
#include "gui_main.h"
#include <QApplication>
#include "main.h"
#include <QSqlDatabase>
#include "math.h"
#include "gui_login.h"

//
// class: Main
//
class Main m;

/*
================
entry point
================
*/
int main(int argc, char *argv[]) {
    QApplication app( argc, argv );

    // initialize core
    m.initialize();

    // display main activity
    Gui_Main w;
    w.show();
    w.initialize();
    w.setDisabled( true );

    // display login
    Gui_Login login( &w );
    login.exec();

    return app.exec();
}

/*
================
initialize
================
*/
void Main::initialize() {
    this->setInitialized( false );
    this->loadDatabase();
    this->setInitialized();
}

/*
================
print
================
*/
void Main::print( const QString &msg ) {
#ifdef APPLET_DEBUG
    qDebug() << msg;
#endif
}

/*
================
error
================
*/
void Main::error( ErrorTypes type, const QString &msg ) {
    if ( type == FatalError ) {
        this->print( this->tr( "FATAL ERROR: %1" ).arg( msg ));
        this->shutdown();
    } else
        this->print( this->tr( "ERROR: %1" ).arg( msg ));
}

/*
================
shutdown
================
*/
void Main::shutdown( bool ignoreDatabase ) {
    // TODO: delete orphaned logs on shutdown
    if ( !ignoreDatabase ) {
        // close database if open
        QSqlDatabase db = QSqlDatabase::database();
        if ( db.open()) {
            this->removeOrphanedLogs();
            db.close();
        }
    }

    // TODO: store lastUser, lastTemplate, lastPrecursor

    // reset initialization state
    this->setInitialized( false );

    // close applet
    QApplication::quit();
}

/*
================
fillUnits
================
*/
void Main::fillUnits( QComboBox *cPtr, bool isSolvent ) {
    int y;

    // clear container
    cPtr->clear();

    // add precursor strings
    for ( y = 0; y < Common::numUnits; y++ ) {
        Common::Units units = static_cast<Common::Units>( y );

        if ( !isSolvent && (( units == Common::Millilitres ) || ( units == Common::Litres )))
            continue;

        cPtr->addItem( Common::UnitsStrings[y], QVariant( units ));
    }
}

/*
================
unitsToIndex
================
*/
int Main::unitsToIndex( QComboBox *cPtr, Common::Units units ) {
    int y;

    for ( y = 0; y < cPtr->count(); y++ ) {
        if ( !QString::compare( cPtr->itemText( y ), Common::UnitsStrings[units] ))
            return y;
    }
    return -1;
}

/*
================
indexToUnits
================
*/
Common::Units Main::indexToUnits( QComboBox *cPtr ) {
    int y;

    for ( y = 0; y < Common::numUnits; y++ ) {
        if ( !QString::compare( cPtr->currentText(), Common::UnitsStrings[y] ))
            return static_cast<Common::Units>( y );
    }
    return Common::Grams;
}

/*
================
getPrecision
================
*/
int Main::getPrecision( Common::Units units ) {
    // TODO: make this changable in settings

    // get precision
    switch ( units ) {
    case Common::Grams:
    case Common::Millilitres:
        return 1;
        break;
    case Common::Kilograms:
    case Common::Litres:
        return 4;
        break;

    default:
        return 0;
    }
}

/*
================
amountTo
================
*/
float Main::convert( float amount, Common::Units baseUnits, Common::Units units, float density ) {
    float convAmount = amount;

    if ( baseUnits != units ) {
        switch ( units ) {
        case Common::Kilograms:
            if ( baseUnits == Common::Grams ) // kg->g
                convAmount *= 1000.0f;
            else if ( baseUnits == Common::Millilitres ) // kg->ml
                convAmount *= ( 1000.0f / density );
            else if ( baseUnits == Common::Litres ) // kg->L
                convAmount /= density;
            break;

        case Common::Litres:
            if ( baseUnits == Common::Grams ) // L->g
                convAmount *= ( 1000.0f * density );
            else if ( baseUnits == Common::Millilitres ) // L->ml
                convAmount *= 1000.0f;
            else if ( baseUnits == Common::Kilograms ) // L->kg
                convAmount *= density;
            break;

        case Common::Millilitres:
            if ( baseUnits == Common::Grams ) // ml->g
                convAmount *= density;
            else if ( baseUnits == Common::Litres ) // ml->L
                convAmount /= 1000.0f;
            else if ( baseUnits == Common::Kilograms ) // ml->kg
                convAmount /= ( 1000.0f * density );
            break;

        case Common::Grams:
            if ( baseUnits == Common::Millilitres ) // g->ml
                convAmount /= density;
            else if ( baseUnits == Common::Litres ) // g->L
                convAmount /= ( 1000.0f / density );
            else if ( baseUnits == Common::Kilograms ) // g->kg
                convAmount /= 1000.0f;
            break;

        default:
            m.error( Main::SoftError, QString( "Main::convert invalid units '%1'\n" ).arg( static_cast<int>( units )));
        }
    }
    return convAmount;
}
